package com.ouc.yyi.springcloud.gateway.filter.response;

import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.ouc.yyi.springcloud.gateway.consts.Const;
import com.ouc.yyi.springcloud.gateway.filter.response.result.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;

/**
 * @description: 响应拦截器，对响应结果进行解密
 * @author: yyi
 * @date: 2022/9/16 9:14
 * @version: 1.0
 **/
@Component
@Slf4j
public class EncryptionFilter implements GlobalFilter, Ordered {

    private final SymmetricCrypto sm4 = SmUtil.sm4(Const.EN_KEY.getBytes());
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("进入响应拦截器，对请求的参数进行加密操作");
        HttpMethod method = exchange.getRequest().getMethod();
        if (method != HttpMethod.POST) {
            return chain.filter(exchange);
        }
        //构建响应拦截处理器
        BodyHandlerFunction bodyHandler = (resp, body) -> Flux.from(body)
                .map(dataBuffer -> {
                    //响应信息转换为字符串
                    return IoUtil.read(dataBuffer.asInputStream(), Charset.defaultCharset());
                })
                .flatMap(orgBody -> {
                    //根据原有的响应信息构建新响应信息并写入到resp
                    log.info("*********  response拦截器解密[前]的responseBody  "+orgBody);
                    String enBody = sm4.encryptHex(orgBody, Charset.defaultCharset());
                    ResponseVo build = ResponseVo.builder().msg1(enBody).build();
                    String result = JSONUtil.parseObj(build).toString();
                    log.info("*********  response拦截器解密[后]的responseBody  "+ enBody);
                    return resp.writeWith(Flux.just(result)
                            .map(bx -> resp.bufferFactory()
                                    .wrap(bx.getBytes())));
                }).then();

        //构建响应包装类
        BodyHandlerServerHttpResponseDecorator responseDecorator = new BodyHandlerServerHttpResponseDecorator(bodyHandler, exchange.getResponse());
        return chain
                .filter(exchange.mutate().response(responseDecorator).build());
    }

    /**
     * 该拦截器的执行顺序确保在WRITE_RESPONSE_FILTER_ORDER之前执行
     * */
    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }
}
